<!-- 

  Author profile：

  欢迎您朋友，感谢你的认可，我是几何心凉
  CSDN博客专家、内容合伙人、新星计划导师，
  Vue技能树构建者、阿里云社区专家博主，
  前端领域优质创作者致力于新技术的推广与优秀技术的普及。

  可提供简历、就业指导服务

  CSDN博客：https://blog.csdn.net/JHXL_
  公众号：#几何心凉的核心圈
  
 -->

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>凉哥的简易版贪吃蛇</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }

      p {
        text-align: center;
        font-size: 23px;
        font-weight: 600;
      }

      .gamBox {
        width: 500px;
        height: 500px;
        border: 10px solid #393c1b;
        margin: 20px auto;
        background-color: #b6b327;
        border-radius: 20px;
        display: flex;
        flex-direction: column;
        justify-content: space-around;
        align-items: center;
      }

      /* //下方等级、得分盒子/ */
      .integral {
        width: 398px;
        height: 25px;
        display: flex;
        justify-content: space-between;
        font-size: 16px;
        font-family: "Trebuchet MS", "Lucida Sans Unicode", "Lucida Grande",
          "Lucida Sans", Arial, sans-serif;
        font-weight: 700;
      }

      /* //屏幕样式 */
      .screen {
        width: 400px;
        height: 400px;
        border: 1px solid #000;
        position: relative;
      }

      /* //蛇的样式 */
      .snake .snake-head {
        width: 20px;
        height: 20px;
        border: 1px solid #4d7d2b;
        background-color: #000;
        position: absolute;
        top: 0;
        left: 0;
      }

      .snake span {
        font-size: 17px;
        position: absolute;
        left: -2.7px;
        top: -3px;
      }

      .snake-body > div {
        position: absolute;
        top: 0;
        left: 0;
        width: 20px;
        height: 20px;
        border: 1px solid #4d7d2b;
        background-color: #000;
      }

      /* //食物的样式 */

      .food {
        width: 20px;
        height: 20px;
        font-size: 8px;
        text-align: left;
        position: absolute;
        top: 10px;
        left: 0;
      }

      .food span {
        font-size: 17px;
        position: absolute;
        left: -1.7px;
        top: -2px;
      }
    </style>
  </head>

  <body>
    <p>贪吃蛇</p>
    <div class="gamBox">
      <div class="screen">
        <div class="snake">
          <div class="snake-head">
            <span>😁</span>
          </div>
          <div class="snake-body"></div>
        </div>

        <div class="food">
          <span>🐷</span>
        </div>
      </div>
      <div class="integral">
        <div>等级（grade）<span class="grade"></span></div>
        <div>分数（score）<span class="score"></span></div>
      </div>
    </div>
  </body>

  <script>
    /***
     * 公用变量
     * @foundationNumber 基础倍数：移动、食物随机位置量的倍数
     * @maxGrade 最大的等级
     */

    const foundationNumber = 20;
    const maxGrade = 10;

    /***
     * 食物相关
     */
    const randomNumber = (min, max) => {
      return Math.floor(Math.random() * (max - min)) + min;
    };
    let foodSeat = {
      top: 20,
      left: 20,
    };
    const changeFoodSeat = () => {
      foodSeat.top = randomNumber(0, 20) * foundationNumber;
      foodSeat.left = randomNumber(0, 20) * foundationNumber;

      document.querySelector(".food").style.cssText =
        "left:" + foodSeat.left + "px;top:" + foodSeat.top + "px";
    };

    /***
     * 等级、分数相关
     */
    let register = {
      score: 0,
      grade: 1,
    };
    const changeScore = () => {
      register.score++;
      if (register.grade < 10) {
        register.grade = Math.ceil(register.score / 10);
      }

      document.querySelector(".grade").innerText = register.grade;
      document.querySelector(".score").innerText = register.score;
    };

    /***
     * 蛇相关
     */

    let direction = ""; //移动方向
    let snakeLength = [];
    let snakeSeat = {
      top: 0,
      left: 0,
    };
    const handleWatchEnter = (e) => {
      let previousTop = snakeSeat.top;
      let previousLeft = snakeSeat.left;
      //通过便利每个身体部分来进行移动
      snakeLength.forEach((ele, index) => {
        let temporaryTop = ele.top;
        let temporaryLeft = ele.left;
        ele.top = previousTop;
        ele.left = previousLeft;
        previousTop = temporaryTop;
        previousLeft = temporaryLeft;
        document.querySelectorAll(".snake-body>div")[index].style.cssText =
          "left:" + ele.left + "px;top:" + ele.top + "px";
      });

      switch (direction) {
        case "ArrowUp":
          snakeSeat.top -= 20;
          break;
        case "ArrowLeft":
          snakeSeat.left -= 20;
          break;
        case "ArrowRight":
          snakeSeat.left += 20;
          break;
        case "ArrowDown":
          snakeSeat.top += 20;
          break;
      }

      if (snakeSeat.top == foodSeat.top && snakeSeat.left == foodSeat.left) {
        changeScore();
        changeFoodSeat();
        snakeLength.push({
          top: previousTop,
          left: previousLeft,
        });

        var div = document.createElement("div");
        div.style.left = previousLeft + "px";
        div.style.top = previousTop + "px";
        div.class = "bodyItem";

        document.querySelector(".snake-body").appendChild(div);
      }

      if (
        snakeSeat.top < 0 ||
        snakeSeat.left < 0 ||
        snakeSeat.left > 380 ||
        snakeSeat.top > 380
      ) {
        alert("撞墙身亡");
        snakeSeat.top = 0;
        snakeSeat.left = 0;
        direction = "";
        snakeLength = [];
        init();

        return;
      }

      let bodySeats = snakeLength.map((item) => JSON.stringify(item));

      if (
        bodySeats.indexOf(
          JSON.stringify({ top: snakeSeat.top, left: snakeSeat.left })
        ) != -1
      ) {
        alert("把自己撞死了");
        snakeSeat.top = 0;
        snakeSeat.left = 0;
        snakeLength = [];
        direction = "";
        init();
        return;
      }
      document.querySelector(".snake-head").style.cssText =
        "left:" + snakeSeat.left + "px;top:" + snakeSeat.top + "px";
      setTimeout(() => {
        handleWatchEnter();
      }, 400 - (register.grade - 1) * 15);
    };

    //函数节流
    const throttle = (fn, wait) => {
      var timer = null;
      return function () {
        var _this = this;
        var args = arguments;
        if (!timer) {
          timer = setTimeout(function () {
            fn.apply(_this, args);
            timer = null;
          }, wait);
        }
      };
    };

    const init = () => {
      document.querySelector(".snake-head").style.cssText =
        "left:" + 0 + "px;top:" + 0 + "px";
      document.querySelector(".snake-body").innerHTML = "";
      document.querySelector(".grade").innerText = register.grade;
      document.querySelector(".score").innerText = register.score;
      changeFoodSeat();
      handleWatchEnter();
    };

    document.addEventListener("keydown", (e) => {
      if (
        (e.code == "ArrowUp" && direction != "ArrowDown") ||
        (e.code == "ArrowLeft" && direction != "ArrowRight") ||
        (e.code == "ArrowRight" && direction != "ArrowLeft") ||
        (e.code == "ArrowDown" && direction != "ArrowUp")
      ) {
        direction = e.code;
      }
    });
    init();
  </script>
</html>

